package com.woniuxy.commons.config;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;

import com.woniuxy.commons.filter.PhoneCodeAuthenticationFilter;
import com.woniuxy.commons.filter.RoleFilter;
import com.woniuxy.commons.handler.LoginErrorHandler;
import com.woniuxy.commons.handler.LoginSuccessHandler;
import com.woniuxy.dao.UriInfoDao;
import com.woniuxy.service.AccountService;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import javax.annotation.Resource;

@Configuration
//@EnableGlobalMethodSecurity(prePostEnabled = true)//配置权限方式二（AOP）开启  去Controller的方法上加@PreAuthorize("hasAnyAuthority('自定义权限')")
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    public PasswordEncoder createPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Resource
    private LoginErrorHandler loginErrorHandler;

    @Resource
    private LoginSuccessHandler loginSuccessHandler;

    @Resource
    private AccountService accountService;


    @Resource
    private UriInfoDao uriInfoDao;

    @Resource
    private StringRedisTemplate str;



    //乐观锁插件 mybatis-plus插件
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        //乐观锁插件
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        //添加分页插件
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }

    //配置跨域
    public CorsConfigurationSource ceateCorsConfigurationSource() {
        //创建url的跨域拦截设置对象
        UrlBasedCorsConfigurationSource uccf = new UrlBasedCorsConfigurationSource();
        //创建跨域的参数设置对象
        CorsConfiguration cc = new CorsConfiguration();
        //设置允许的跨域地址
        cc.addAllowedOriginPattern("*");
        //设置允许的header
        cc.addAllowedHeader("*");
        //设置允许的请求方式
        cc.addAllowedMethod("*");
        //设置允许携带cookie
        cc.setAllowCredentials(true);
        //对所有的url拦截进行设置，设置的参数是CorsConfiguration
        uccf.registerCorsConfiguration("/**", cc);
        return uccf;
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        PhoneCodeAuthenticationFilter phoneCodeAuthenticationFilter = new PhoneCodeAuthenticationFilter(accountService,uriInfoDao,str);
        phoneCodeAuthenticationFilter.setAuthenticationSuccessHandler(loginSuccessHandler);
        phoneCodeAuthenticationFilter.setAuthenticationFailureHandler(loginErrorHandler);


        http.httpBasic().disable()
                //配置权限
                .addFilterAfter(new RoleFilter(), FilterSecurityInterceptor.class)
                .addFilterAfter(phoneCodeAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
                //关闭csrf（跨站伪造攻击）
                .csrf().disable()
                //配置URI资源拦截器规则
                .authorizeRequests()
                .antMatchers("/swagger-ui.html","/v2/api-docs","/webjars/**",
                        "/swagger-resources/**","/account/sendCode","/account/activation","/account/login","/login","/phoneLogin","/account/register","/logout","/account/errorlogin","/**").permitAll()//类似于过滤器放行的URL请求，可以写多个
                //.antMatchers("/teacher/getTeacher").hasAuthority("user")//
                // 配置权限方式一：第一个括号（antMatchers）表示访问的地址，第二个括号（hasAuthority）表示访问该地址需要什么权限（自定义），是通过Security的；拦截器实现的
                .anyRequest().authenticated()//除了上面配置的，都拦截
                .and()//返回到上一层级（authorizeRequests这一层）
                //配置账号密码登陆流程
            .formLogin()
                //设置登陆访问的url
                .loginProcessingUrl("/account/login")
                //设置未登录的跳转地址html
                .loginPage("/account/errorlogin")
                .successHandler(loginSuccessHandler)
                .failureHandler(loginErrorHandler)
                .and()
            .cors()
                .configurationSource(ceateCorsConfigurationSource());
    }
}
